package com.example.network

import com.alibaba.android.arouter.launcher.ARouter
import com.blankj.utilcode.util.EncryptUtils
import com.tencent.mmkv.MMKV
import okhttp3.Interceptor
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.OkHttpClient
import okhttp3.RequestBody.Companion.toRequestBody
import okhttp3.Response
import okhttp3.ResponseBody.Companion.toResponseBody
import okhttp3.logging.HttpLoggingInterceptor
import org.json.JSONObject
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import java.security.SecureRandom
import java.security.cert.X509Certificate
import java.util.concurrent.TimeUnit
import javax.net.ssl.SSLContext
import javax.net.ssl.SSLSocketFactory
import javax.net.ssl.X509TrustManager


/**
 * 网络管理对象
 */
object HttpManager {


    //获取OkHttpClient对象实例
    private fun getOkHttpClient(type: HttpInterceptorType): OkHttpClient {
        var okBuilder = OkHttpClient.Builder()
        //添加接口日志拦截器
        if (BuildConfig.isOpenLog){
            okBuilder.addInterceptor(HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY))
        }
        //设置超时时间
        okBuilder.connectTimeout(10, TimeUnit.SECONDS)
        okBuilder.readTimeout(10, TimeUnit.SECONDS)
        okBuilder.writeTimeout(10, TimeUnit.SECONDS)

        //根据类型添加不同的拦截器
        when(type){
            HttpInterceptorType.SIGN -> {
                okBuilder.addInterceptor(getSignInterceptor())
            }

            HttpInterceptorType.TOKEN -> {
                okBuilder.addInterceptor(getTokenInterceptor())
            }

            HttpInterceptorType.UPLOAD ->{
                okBuilder.readTimeout(3, TimeUnit.MINUTES)
                okBuilder.writeTimeout(3, TimeUnit.MINUTES)
            }

            HttpInterceptorType.INTERCEPTOR -> {
//                okBuilder.addInterceptor(getTokenInterceptor())
//                okBuilder.addInterceptor(getSignInterceptor())
            }
        }

        //添加服务器错误拦截器
        okBuilder.addInterceptor(getServerErrorInterceptor())

        //添加Https支持
        okBuilder.sslSocketFactory(sslSocketFactory, trustManager)

        return okBuilder.build()
    }

    /**
     * 对称加密与非对称加密的区别
     * 1.对称加密：加密和解密使用同一个串，非对称加密的加密串分为公钥和私钥，私钥一般放在服务端，公钥属于公开密钥串
     * 2.非对称加密流程：
     *   场景一：服务端 ---> 客户端发送数据   服务端使用私钥串加密数据    ---->  客户端使用公钥串解密数据
     *   场景二：客户端 ---> 服务端发送数据   客户端使用公钥串加密数据    ---->  服务端使用私钥串解密数据
     * 3.对称加密流程：
     *   场景一：服务端 ---> 客户端发送数据   服务端使用公钥串加密数据    ---->  客户端使用公钥串解密数据
     *   场景二：客户端 ---> 服务端发送数据   客户端使用公钥串加密数据    ---->  服务端使用公钥串解密数据
     */
    private val sslSocketFactory: SSLSocketFactory
        get() = try {
            val sslContext = SSLContext.getInstance("SSL")
            sslContext.init(null, arrayOf(trustManager), SecureRandom())
            sslContext.socketFactory
        } catch (e: Exception){
            throw RuntimeException(e)
        }

    private val trustManager: X509TrustManager
        get() = object : X509TrustManager{
            override fun checkClientTrusted(chain: Array<out X509Certificate>?, authType: String?) {}

            override fun checkServerTrusted(chain: Array<out X509Certificate>?, authType: String?) {}

            override fun getAcceptedIssuers(): Array<X509Certificate> {
                return arrayOf()
            }
        }


    //获取Retrofit对象实例
    private fun getRetrofit(type: HttpInterceptorType): Retrofit {
        return Retrofit.Builder()
            .baseUrl(BuildConfig.BASE_URL)
            .client(getOkHttpClient(type))
            .addConverterFactory(GsonConverterFactory.create())
            .build()
    }


    /**
     * 获取Token拦截器
     */
    private fun getTokenInterceptor(): Interceptor {
        return object : Interceptor {
            override fun intercept(chain: Interceptor.Chain): Response {
                var token = MMKV.defaultMMKV().decodeString("token")
                if (!token.isNullOrEmpty()){
                    var newRequest = chain.request().newBuilder().header("token", token).build()
                    var response = chain.proceed(newRequest)
                    //如果Token过期，则重新登录
                    if (response.code == 403){
                        ARouter.getInstance().build("/login/activity").navigation()
                    }
                    return  response
                }
                return chain.proceed(chain.request())
            }
        }
    }


    /**
     * 获取签名拦截器
     */
    private fun getSignInterceptor(): Interceptor{
        return object : Interceptor{
            override fun intercept(chain: Interceptor.Chain): Response {
                var oldRequest = chain.request()
                try {
                    var builder = oldRequest.newBuilder()
                    builder.url(oldRequest.url)
                    builder.headers(oldRequest.headers)

                    //获取参数
                    var buf = okio.Buffer()
                    var reqBody = oldRequest.body
                    reqBody?.writeTo(buf)
                    var bodyStr = buf.toString()
                    buf.close()

                    bodyStr = bodyStr.substring(bodyStr.indexOf("{"), bodyStr.lastIndexOf("}") + 1)
                    var reqJsonObj = JSONObject(bodyStr)

                    //拼接参数
                    var sb = StringBuffer()
                    var keys = reqJsonObj.keys()
                    while (keys.hasNext()){
                        sb.append(reqJsonObj.getString(keys.next()))
                    }

                    //使用MD5加密
                    var signMd5 = getMd5Encrypt(sb.toString())
                    reqJsonObj.put("sign", signMd5)

                    //重新请求Body
                    var newJson = reqJsonObj.toString()
                    var newBody = newJson.toRequestBody("application/json; charset=utf-8".toMediaTypeOrNull())
                    builder.post(newBody)

                    //获取新的Request对象
                    var newRequest = builder.build()
                    return chain.proceed(newRequest)
                } catch (e: Exception){
                    e.printStackTrace()
                    return chain.proceed(oldRequest)
                }
            }
        }
    }

    /**
     * 服务器错误拦截器
     */
    private fun getServerErrorInterceptor(): Interceptor{
        return  object: Interceptor{
            override fun intercept(chain: Interceptor.Chain): Response {
                val oldResponse = chain.proceed(chain.request())
                var builder = oldResponse.newBuilder()
                if (oldResponse.code == 500){
                   var newJson = JSONObject()
                   newJson.put("code", 500)
                   newJson.put("msg", "服务器接口异常，请联系客服！")
                   var body = newJson.toString().toResponseBody("application/json; charset=utf-8".toMediaTypeOrNull())
                   builder.body(body)
                }
                return builder.build()
            }
        }
    }

    /**
     * 获取MD5值
     */
    fun getMd5Encrypt(originStr: String): String{
        return EncryptUtils.encryptMD5ToString("${originStr}tamboo").lowercase()
    }

    /**
     * 获取业务接口实例
     */
    fun <T> createApiServer(clazz: Class<*>, type: HttpInterceptorType): T {
        return getRetrofit(type).create(clazz) as T
    }

}